/*!
 * # Semantic UI 2.4.1 - Dimmer
 * http://github.com/semantic-org/semantic-ui/
 *
 *
 * Released under the MIT license
 * http://opensource.org/licenses/MIT
 *
 */

;(function ($, window, document, undefined) {

    'use strict';

    window = (typeof window != 'undefined' && window.Math == Math)
        ? window
        : (typeof self != 'undefined' && self.Math == Math)
            ? self
            : Function('return this')()
    ;

    $.fn.dimmer = function (parameters) {
        var
            $allModules = $(this),

            time = new Date().getTime(),
            performance = [],

            query = arguments[0],
            methodInvoked = (typeof query == 'string'),
            queryArguments = [].slice.call(arguments, 1),

            returnedValue
        ;

        $allModules
            .each(function () {
                var
                    settings = ($.isPlainObject(parameters))
                        ? $.extend(true, {}, $.fn.dimmer.settings, parameters)
                        : $.extend({}, $.fn.dimmer.settings),

                    selector = settings.selector,
                    namespace = settings.namespace,
                    className = settings.className,
                    error = settings.error,

                    eventNamespace = '.' + namespace,
                    moduleNamespace = 'module-' + namespace,
                    moduleSelector = $allModules.selector || '',

                    clickEvent = ('ontouchstart' in document.documentElement)
                        ? 'touchstart'
                        : 'click',

                    $module = $(this),
                    $dimmer,
                    $dimmable,

                    element = this,
                    instance = $module.data(moduleNamespace),
                    module
                ;

                module = {

                    preinitialize: function () {
                        if (module.is.dimmer()) {

                            $dimmable = $module.parent();
                            $dimmer = $module;
                        }
                        else {
                            $dimmable = $module;
                            if (module.has.dimmer()) {
                                if (settings.dimmerName) {
                                    $dimmer = $dimmable.find(selector.dimmer).filter('.' + settings.dimmerName);
                                }
                                else {
                                    $dimmer = $dimmable.find(selector.dimmer);
                                }
                            }
                            else {
                                $dimmer = module.create();
                            }
                        }
                    },

                    initialize: function () {
                        module.debug('Initializing dimmer', settings);

                        module.bind.events();
                        module.set.dimmable();
                        module.instantiate();
                    },

                    instantiate: function () {
                        module.verbose('Storing instance of module', module);
                        instance = module;
                        $module
                            .data(moduleNamespace, instance)
                        ;
                    },

                    destroy: function () {
                        module.verbose('Destroying previous module', $dimmer);
                        module.unbind.events();
                        module.remove.variation();
                        $dimmable
                            .off(eventNamespace)
                        ;
                    },

                    bind: {
                        events: function () {
                            if (settings.on == 'hover') {
                                $dimmable
                                    .on('mouseenter' + eventNamespace, module.show)
                                    .on('mouseleave' + eventNamespace, module.hide)
                                ;
                            }
                            else if (settings.on == 'click') {
                                $dimmable
                                    .on(clickEvent + eventNamespace, module.toggle)
                                ;
                            }
                            if (module.is.page()) {
                                module.debug('Setting as a page dimmer', $dimmable);
                                module.set.pageDimmer();
                            }

                            if (module.is.closable()) {
                                module.verbose('Adding dimmer close event', $dimmer);
                                $dimmable
                                    .on(clickEvent + eventNamespace, selector.dimmer, module.event.click)
                                ;
                            }
                        }
                    },

                    unbind: {
                        events: function () {
                            $module
                                .removeData(moduleNamespace)
                            ;
                            $dimmable
                                .off(eventNamespace)
                            ;
                        }
                    },

                    event: {
                        click: function (event) {
                            module.verbose('Determining if event occured on dimmer', event);
                            if ($dimmer.find(event.target).length === 0 || $(event.target).is(selector.content)) {
                                module.hide();
                                event.stopImmediatePropagation();
                            }
                        },
                    },

                    addContent: function (element) {
                        var
                            $content = $(element)
                        ;
                        module.debug('Add content to dimmer', $content);
                        if ($content.parent()[0] !== $dimmer[0]) {
                            $content.detach().appendTo($dimmer);
                        }
                    },

                    create: function () {
                        var
                            $element = $(settings.template.dimmer())
                        ;
                        if (settings.dimmerName) {
                            module.debug('Creating named dimmer', settings.dimmerName);
                            $element.addClass(settings.dimmerName);
                        }
                        $element
                            .appendTo($dimmable)
                        ;
                        return $element;
                    },

                    show: function (callback) {
                        callback = $.isFunction(callback)
                            ? callback
                            : function () {
                            }
                        ;
                        module.debug('Showing dimmer', $dimmer, settings);
                        module.set.variation();
                        if ((!module.is.dimmed() || module.is.animating()) && module.is.enabled()) {
                            module.animate.show(callback);
                            settings.onShow.call(element);
                            settings.onChange.call(element);
                        }
                        else {
                            module.debug('Dimmer is already shown or disabled');
                        }
                    },

                    hide: function (callback) {
                        callback = $.isFunction(callback)
                            ? callback
                            : function () {
                            }
                        ;
                        if (module.is.dimmed() || module.is.animating()) {
                            module.debug('Hiding dimmer', $dimmer);
                            module.animate.hide(callback);
                            settings.onHide.call(element);
                            settings.onChange.call(element);
                        }
                        else {
                            module.debug('Dimmer is not visible');
                        }
                    },

                    toggle: function () {
                        module.verbose('Toggling dimmer visibility', $dimmer);
                        if (!module.is.dimmed()) {
                            module.show();
                        }
                        else {
                            module.hide();
                        }
                    },

                    animate: {
                        show: function (callback) {
                            callback = $.isFunction(callback)
                                ? callback
                                : function () {
                                }
                            ;
                            if (settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) {
                                if (settings.useFlex) {
                                    module.debug('Using flex dimmer');
                                    module.remove.legacy();
                                }
                                else {
                                    module.debug('Using legacy non-flex dimmer');
                                    module.set.legacy();
                                }
                                if (settings.opacity !== 'auto') {
                                    module.set.opacity();
                                }
                                $dimmer
                                    .transition({
                                        displayType: settings.useFlex
                                            ? 'flex'
                                            : 'block',
                                        animation: settings.transition + ' in',
                                        queue: false,
                                        duration: module.get.duration(),
                                        useFailSafe: true,
                                        onStart: function () {
                                            module.set.dimmed();
                                        },
                                        onComplete: function () {
                                            module.set.active();
                                            callback();
                                        }
                                    })
                                ;
                            }
                            else {
                                module.verbose('Showing dimmer animation with javascript');
                                module.set.dimmed();
                                if (settings.opacity == 'auto') {
                                    settings.opacity = 0.8;
                                }
                                $dimmer
                                    .stop()
                                    .css({
                                        opacity: 0,
                                        width: '100%',
                                        height: '100%'
                                    })
                                    .fadeTo(module.get.duration(), settings.opacity, function () {
                                        $dimmer.removeAttr('style');
                                        module.set.active();
                                        callback();
                                    })
                                ;
                            }
                        },
                        hide: function (callback) {
                            callback = $.isFunction(callback)
                                ? callback
                                : function () {
                                }
                            ;
                            if (settings.useCSS && $.fn.transition !== undefined && $dimmer.transition('is supported')) {
                                module.verbose('Hiding dimmer with css');
                                $dimmer
                                    .transition({
                                        displayType: settings.useFlex
                                            ? 'flex'
                                            : 'block',
                                        animation: settings.transition + ' out',
                                        queue: false,
                                        duration: module.get.duration(),
                                        useFailSafe: true,
                                        onStart: function () {
                                            module.remove.dimmed();
                                        },
                                        onComplete: function () {
                                            module.remove.variation();
                                            module.remove.active();
                                            callback();
                                        }
                                    })
                                ;
                            }
                            else {
                                module.verbose('Hiding dimmer with javascript');
                                module.remove.dimmed();
                                $dimmer
                                    .stop()
                                    .fadeOut(module.get.duration(), function () {
                                        module.remove.active();
                                        $dimmer.removeAttr('style');
                                        callback();
                                    })
                                ;
                            }
                        }
                    },

                    get: {
                        dimmer: function () {
                            return $dimmer;
                        },
                        duration: function () {
                            if (typeof settings.duration == 'object') {
                                if (module.is.active()) {
                                    return settings.duration.hide;
                                }
                                else {
                                    return settings.duration.show;
                                }
                            }
                            return settings.duration;
                        }
                    },

                    has: {
                        dimmer: function () {
                            if (settings.dimmerName) {
                                return ($module.find(selector.dimmer).filter('.' + settings.dimmerName).length > 0);
                            }
                            else {
                                return ($module.find(selector.dimmer).length > 0);
                            }
                        }
                    },

                    is: {
                        active: function () {
                            return $dimmer.hasClass(className.active);
                        },
                        animating: function () {
                            return ($dimmer.is(':animated') || $dimmer.hasClass(className.animating));
                        },
                        closable: function () {
                            if (settings.closable == 'auto') {
                                if (settings.on == 'hover') {
                                    return false;
                                }
                                return true;
                            }
                            return settings.closable;
                        },
                        dimmer: function () {
                            return $module.hasClass(className.dimmer);
                        },
                        dimmable: function () {
                            return $module.hasClass(className.dimmable);
                        },
                        dimmed: function () {
                            return $dimmable.hasClass(className.dimmed);
                        },
                        disabled: function () {
                            return $dimmable.hasClass(className.disabled);
                        },
                        enabled: function () {
                            return !module.is.disabled();
                        },
                        page: function () {
                            return $dimmable.is('body');
                        },
                        pageDimmer: function () {
                            return $dimmer.hasClass(className.pageDimmer);
                        }
                    },

                    can: {
                        show: function () {
                            return !$dimmer.hasClass(className.disabled);
                        }
                    },

                    set: {
                        opacity: function (opacity) {
                            var
                                color = $dimmer.css('background-color'),
                                colorArray = color.split(','),
                                isRGB = (colorArray && colorArray.length == 3),
                                isRGBA = (colorArray && colorArray.length == 4)
                            ;
                            opacity = settings.opacity === 0 ? 0 : settings.opacity || opacity;
                            if (isRGB || isRGBA) {
                                colorArray[3] = opacity + ')';
                                color = colorArray.join(',');
                            }
                            else {
                                color = 'rgba(0, 0, 0, ' + opacity + ')';
                            }
                            module.debug('Setting opacity to', opacity);
                            $dimmer.css('background-color', color);
                        },
                        legacy: function () {
                            $dimmer.addClass(className.legacy);
                        },
                        active: function () {
                            $dimmer.addClass(className.active);
                        },
                        dimmable: function () {
                            $dimmable.addClass(className.dimmable);
                        },
                        dimmed: function () {
                            $dimmable.addClass(className.dimmed);
                        },
                        pageDimmer: function () {
                            $dimmer.addClass(className.pageDimmer);
                        },
                        disabled: function () {
                            $dimmer.addClass(className.disabled);
                        },
                        variation: function (variation) {
                            variation = variation || settings.variation;
                            if (variation) {
                                $dimmer.addClass(variation);
                            }
                        }
                    },

                    remove: {
                        active: function () {
                            $dimmer
                                .removeClass(className.active)
                            ;
                        },
                        legacy: function () {
                            $dimmer.removeClass(className.legacy);
                        },
                        dimmed: function () {
                            $dimmable.removeClass(className.dimmed);
                        },
                        disabled: function () {
                            $dimmer.removeClass(className.disabled);
                        },
                        variation: function (variation) {
                            variation = variation || settings.variation;
                            if (variation) {
                                $dimmer.removeClass(variation);
                            }
                        }
                    },

                    setting: function (name, value) {
                        module.debug('Changing setting', name, value);
                        if ($.isPlainObject(name)) {
                            $.extend(true, settings, name);
                        }
                        else if (value !== undefined) {
                            if ($.isPlainObject(settings[name])) {
                                $.extend(true, settings[name], value);
                            }
                            else {
                                settings[name] = value;
                            }
                        }
                        else {
                            return settings[name];
                        }
                    },
                    internal: function (name, value) {
                        if ($.isPlainObject(name)) {
                            $.extend(true, module, name);
                        }
                        else if (value !== undefined) {
                            module[name] = value;
                        }
                        else {
                            return module[name];
                        }
                    },
                    debug: function () {
                        if (!settings.silent && settings.debug) {
                            if (settings.performance) {
                                module.performance.log(arguments);
                            }
                            else {
                                module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
                                module.debug.apply(console, arguments);
                            }
                        }
                    },
                    verbose: function () {
                        if (!settings.silent && settings.verbose && settings.debug) {
                            if (settings.performance) {
                                module.performance.log(arguments);
                            }
                            else {
                                module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
                                module.verbose.apply(console, arguments);
                            }
                        }
                    },
                    error: function () {
                        if (!settings.silent) {
                            module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
                            module.error.apply(console, arguments);
                        }
                    },
                    performance: {
                        log: function (message) {
                            var
                                currentTime,
                                executionTime,
                                previousTime
                            ;
                            if (settings.performance) {
                                currentTime = new Date().getTime();
                                previousTime = time || currentTime;
                                executionTime = currentTime - previousTime;
                                time = currentTime;
                                performance.push({
                                    'Name': message[0],
                                    'Arguments': [].slice.call(message, 1) || '',
                                    'Element': element,
                                    'Execution Time': executionTime
                                });
                            }
                            clearTimeout(module.performance.timer);
                            module.performance.timer = setTimeout(module.performance.display, 500);
                        },
                        display: function () {
                            var
                                title = settings.name + ':',
                                totalTime = 0
                            ;
                            time = false;
                            clearTimeout(module.performance.timer);
                            $.each(performance, function (index, data) {
                                totalTime += data['Execution Time'];
                            });
                            title += ' ' + totalTime + 'ms';
                            if (moduleSelector) {
                                title += ' \'' + moduleSelector + '\'';
                            }
                            if ($allModules.length > 1) {
                                title += ' ' + '(' + $allModules.length + ')';
                            }
                            if ((console.group !== undefined || console.table !== undefined) && performance.length > 0) {
                                console.groupCollapsed(title);
                                if (console.table) {
                                    console.table(performance);
                                }
                                else {
                                    $.each(performance, function (index, data) {
                                        console.log(data['Name'] + ': ' + data['Execution Time'] + 'ms');
                                    });
                                }
                                console.groupEnd();
                            }
                            performance = [];
                        }
                    },
                    invoke: function (query, passedArguments, context) {
                        var
                            object = instance,
                            maxDepth,
                            found,
                            response
                        ;
                        passedArguments = passedArguments || queryArguments;
                        context = element || context;
                        if (typeof query == 'string' && object !== undefined) {
                            query = query.split(/[\. ]/);
                            maxDepth = query.length - 1;
                            $.each(query, function (depth, value) {
                                var camelCaseValue = (depth != maxDepth)
                                    ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
                                    : query
                                ;
                                if ($.isPlainObject(object[camelCaseValue]) && (depth != maxDepth)) {
                                    object = object[camelCaseValue];
                                }
                                else if (object[camelCaseValue] !== undefined) {
                                    found = object[camelCaseValue];
                                    return false;
                                }
                                else if ($.isPlainObject(object[value]) && (depth != maxDepth)) {
                                    object = object[value];
                                }
                                else if (object[value] !== undefined) {
                                    found = object[value];
                                    return false;
                                }
                                else {
                                    module.error(error.method, query);
                                    return false;
                                }
                            });
                        }
                        if ($.isFunction(found)) {
                            response = found.apply(context, passedArguments);
                        }
                        else if (found !== undefined) {
                            response = found;
                        }
                        if ($.isArray(returnedValue)) {
                            returnedValue.push(response);
                        }
                        else if (returnedValue !== undefined) {
                            returnedValue = [returnedValue, response];
                        }
                        else if (response !== undefined) {
                            returnedValue = response;
                        }
                        return found;
                    }
                };

                module.preinitialize();

                if (methodInvoked) {
                    if (instance === undefined) {
                        module.initialize();
                    }
                    module.invoke(query);
                }
                else {
                    if (instance !== undefined) {
                        instance.invoke('destroy');
                    }
                    module.initialize();
                }
            })
        ;

        return (returnedValue !== undefined)
            ? returnedValue
            : this
            ;
    };

    $.fn.dimmer.settings = {

        name: 'Dimmer',
        namespace: 'dimmer',

        silent: false,
        debug: false,
        verbose: false,
        performance: true,

        // whether should use flex layout
        useFlex: true,

        // name to distinguish between multiple dimmers in context
        dimmerName: false,

        // whether to add a variation type
        variation: false,

        // whether to bind close events
        closable: 'auto',

        // whether to use css animations
        useCSS: true,

        // css animation to use
        transition: 'fade',

        // event to bind to
        on: false,

        // overriding opacity value
        opacity: 'auto',

        // transition durations
        duration: {
            show: 500,
            hide: 500
        },

        onChange: function () {
        },
        onShow: function () {
        },
        onHide: function () {
        },

        error: {
            method: 'The method you called is not defined.'
        },

        className: {
            active: 'active',
            animating: 'animating',
            dimmable: 'dimmable',
            dimmed: 'dimmed',
            dimmer: 'dimmer',
            disabled: 'disabled',
            hide: 'hide',
            legacy: 'legacy',
            pageDimmer: 'page',
            show: 'show'
        },

        selector: {
            dimmer: '> .ui.dimmer',
            content: '.ui.dimmer > .content, .ui.dimmer > .content > .center'
        },

        template: {
            dimmer: function () {
                return $('<div />').attr('class', 'ui dimmer');
            }
        }

    };

})(jQuery, window, document);
